/*******************************************************************************
 *	                           bsp ram clear.c
 *******************************************************************************/
#include "bsp.h"
#include "pincfg.h"
#include "stm32f1xx_ll_spi.h"
#include "../CH395Q/ch395_cmd.h"

#define SPIX SPI1
#define ISR_IRQn SPI1_IRQn

void eth_spi_init(void);
void eth_spi_cs(uint8_t st);
uint8_t eth_spi_rb(void);
void eth_spi_wb(uint8_t dataW);
uint8_t eth_spi_rw(uint8_t dataW);
uint8_t eth_spi_write(const uint8_t *dataw, uint32_t Len);
uint8_t eth_spi_read(uint8_t *datar, uint32_t Len);

/*****************************************************************************
 * @brief   hal init.
 *
 * @param   none
 *
 * @return  none
 *
 * @ Pass/ Fail criteria: none
 *****************************************************************************/
void eth_spi_init(void)
{
	LL_SPI_InitTypeDef cfg;

	__HAL_RCC_SPI1_CLK_ENABLE();

	cfg.Mode = LL_SPI_MODE_MASTER;
	cfg.TransferDirection = LL_SPI_FULL_DUPLEX;
	cfg.ClockPhase = LL_SPI_PHASE_2EDGE;
	cfg.ClockPolarity = LL_SPI_POLARITY_HIGH;
	cfg.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV4;
	cfg.BitOrder = LL_SPI_MSB_FIRST;
	cfg.NSS = LL_SPI_NSS_SOFT;
	cfg.DataWidth = LL_SPI_DATAWIDTH_8BIT;
	cfg.CRCPoly = LL_SPI_CRCCALCULATION_DISABLE;
	LL_SPI_Init(SPIX, &cfg);

	SPIX->CR1 |= SPI_CR1_SPE;

	eth_spi_cs(0);

	eth_spi_rb();

	eth_spi_cs(1);
}

/*****************************************************************************
 * @brief   cs ctr.
 * @param   st
 * @return  none
 * @ Pass/ Fail criteria: none
 *****************************************************************************/
void eth_spi_cs(uint8_t st)
{
	eth_cs.out(st);
}

void eth_spi_cs_high(void)
{
	eth_cs.en();
}

void eth_spi_low(void)
{
	eth_cs.dis();
}

/*****************************************************************************
 * @brief   spi delay.
 *****************************************************************************/
#define spi_read_delay() NOP8()
#define is_spi_rx_ready(spix) ((spix->SR & SPI_SR_RXNE) != 0)
#define spi_rx_reset(spix)               \
	while (is_spi_rx_ready(spix))        \
	{                                    \
		volatile uint32_t rd = spix->DR; \
	}
#define is_spi_busy(spix) (spix->SR & SPI_SR_BSY)
#define spi_send(spix, dat) spix->DR = dat
#define is_spi_tx_full(spix) ((spix->SR & SPI_SR_TXE) == 0)
#define is_spi_tx_empty(spix) (spix->SR & SPI_SR_TXE)
#define spi_read(spix) spix->DR

/*****************************************************************************
 * @brief   spi data read.
 *****************************************************************************/
uint8_t eth_spi_rb(void)
{
	// send data
	spi_send(SPIX, 0xFF);
	spi_read_delay();

	// wait for trans complete
	while (!is_spi_rx_ready(SPIX))
		;

	// read data
	return (spi_read(SPIX));
}

void eth_spi_wb(uint8_t dataW)
{
	volatile uint8_t rb;

	// send data
	spi_send(SPIX, dataW);
	spi_read_delay();

	// wait for trans complete
	while (!is_spi_rx_ready(SPIX))
		;

	// read data
	rb = spi_read(SPIX);
}

uint8_t eth_spi_rw(uint8_t dataW)
{
	// send data
	spi_send(SPIX, dataW);
	spi_read_delay();

	// wait for trans complete
	while (!is_spi_rx_ready(SPIX))
		;

	// read data
	return spi_read(SPIX);
}

/*****************************************************************************
 * @brief   spi data write.
 *****************************************************************************/
uint8_t eth_spi_write(const uint8_t *dataw, uint32_t Len)
{
	while (Len--)
	{
		// send data
		spi_send(SPIX, *dataw++);

		spi_read_delay();

		while (is_spi_tx_full(SPIX))
		{
		}
	}

	spi_read_delay();

	// wait for trans complete
	while (is_spi_busy(SPIX) || !is_spi_tx_empty(SPIX))
	{
	}

	spi_rx_reset(SPIX);

	return (0);
}

/*****************************************************************************
 * @brief   spi data read.
 *****************************************************************************/
uint8_t eth_spi_read(uint8_t *datar, uint32_t Len)
{
	uint32_t rcnt = 0;

	while (Len--)
	{
		// send data
		spi_send(SPIX, 0xFF);

		spi_read_delay();

		while (!is_spi_rx_ready(SPIX))
		{
		}

		datar[rcnt++] = spi_read(SPIX);
	}

	return 0;
}

/*****************************************************************************
 * @brief   int
 *****************************************************************************/
uint8_t eth_int_st(void)
{
	return eth_int.in_st();
}

void eth_rst_opt(uint8_t rst_en)
{
	eth_rst.out(!rst_en);
}

/*****************************************************************************
 * @brief   config
 *****************************************************************************/
const ch395_hal_def_type ch395_spi = {
	.cs_high = eth_spi_cs_high,
	.cs_low = eth_spi_low,
	.int_st = eth_int_st,
	.rst = eth_rst_opt,
	.rb = eth_spi_rb,
	.wb = eth_spi_wb,
	.write = eth_spi_write,
	.read = eth_spi_read,
};